home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / web / noweb / contrib / jonkrom / noxref.nw (.txt) < prev    next >
LaTeX Document  |  1995-02-24  |  19KB  |  420 lines

  1. %=============================================================================
  2. % ----------------------------------------------------------------------------
  3. % Noxref, the cross referencing program for Noweb
  4. \documentstyle[noweb]{article}
  5. %\RCSdef $Id: noxref.nw,v 1.2 1993/05/06 18:15:40 jgk Exp $
  6. % ----------------------------------------------------------------------------
  7. %\title{{\tt Noxref\thanks{\RCSId},}
  8. \title{{\tt Noxref\thanks{Id: noxref.nw,v 1.2 1993/05/06 18:15:40 jgk Exp},}
  9.            the cross referencing program for {\tt Noweb}}
  10. \author{\setcounter{footnote}{6}%
  11.     JG Krom\thanks{JET Joint Undertaking, e-mail address: jgk@jet.uk}}
  12. \date{Printed: \today}
  13. % ----------------------------------------------------------------------------
  14. \makeindex
  15. \begin{document}
  16. \maketitle
  17. % ----------------------------------------------------------------------------
  18. % A bit of jargon:
  19. \newcommand{\noweb}{{\tt noweb}}
  20. \newcommand{\noweave}{{\tt noweave}}
  21. \newcommand{\notangle}{{\tt notangle}}
  22. \newcommand{\noxref}{{\tt noxref}}    \newcommand{\Noxref}{{\tt Noxref}}
  23. \newcommand{\markup}{{\tt markup}}
  24. \newcommand{\awk}{{\rm awk}}
  25. \newcommand{\unix}{{\sc unix}}
  26. \newcommand{\dos}{{\sc msdos}}
  27. \newcommand{\chklist}{{$\setminus$\tt nowebchunks}}
  28. %----------------------------------------------------------------------------
  29. \section{Introduction}
  30. N Ramsey presents in [2] a clean, language independent system for
  31. literate programming, called \noweb.  One of the components of 
  32. \noweave, the ``weave'' program for this system, is the \noxref\ program.
  33. This system has been been ported to \dos\ by L Wittenberg.
  34. The author of this paper customised this \noxref\ program.  The purpose
  35. of this paper is to describe these customisations.  In order to
  36. implement these cutomisations in a ``literate Programming'' style, the
  37. codes written by the above mentioned authors are included in this
  38. document.
  39. % ----------------------------------------------------------------------------
  40. \section{Problem Definition}
  41. The \noxref\ program consists of an \awk\ [1] program, driven by an
  42. \unix\ shell script or, as appropriate, by an \dos\ batch file.  This
  43. \noxref\ program adds page number references to the usage and
  44. definitions of the code chunks in a ``woven'' printing of a literate
  45. program.
  46. A feature that is available in other implementations of the \noxref\
  47. program, the alphabetical chunk list, was missing from the \awk\
  48. implementation of this program.  As this feature seemed useful, it is
  49. implemented as an addition to the existing \noxref\ \awk\ program.
  50. This noxref program is the proper place to create this chunk list,
  51. since all information required for this list is already collected by
  52. this program.
  53. The chunk list should take a form, similar to a table of contents:
  54. chunk names, in the ``\LA{chunk name}\RA{}'' format, on the left hand
  55. side of the page, a list of page numbers on the right hand side of the
  56. page and leaders between the two.  The list of page numbers should first
  57. contain the pages on which the chunk is defined and then the pages on
  58. which the chunk is used.  Root chunks are to be indicated with the word
  59. ``Root''.  Chunks that are used, but not defined, are marked with the
  60. word ``Undefined''.
  61. This whole chunk list, formatted using \LaTeX\ commands, replaces any
  62. line, in the original source, containing only the word ``\chklist''.
  63. \Noxref\ was, and still is, intended as a stage in the \noweave\
  64. pipeline.  This means that it will receive input in the ``marked-up''
  65. format generated by the \markup\ program.  The output of \noxref\
  66. should also be in this format.
  67. % ----------------------------------------------------------------------------
  68. \pagebreak
  69. \section{Web Structure}
  70. This document describes three different files for two different environments:
  71. \begin{enumerate}
  72. \item [[noxref]] The executable shell script for use under \unix.
  73.           This file includes the awk script.
  74. \item [[noxref.bat]] The executable shell script for use under \dos.
  75.           This file calls upon the following file.
  76. \item [[noxref.awk]] The awk source code used or included by the
  77.           files above.  
  78. \end{enumerate}
  79. Each of these can be generated by specifying the required filename as
  80. the root chunk name when executing the \notangle\ program on this web.
  81. To obtain the \dos\ batch file the following command should be executed:
  82. \begin{center}
  83. [[notangle -Rnoxref.bat noxref.nw > noxref.bat]]
  84. \end{center}
  85. Users of these shell scripts might have to adapt the [[awk]] program
  86. name in these scripts to match their local system configuration.
  87. <<noxref>>=
  88. #!/bin/sh
  89. # $Id: noxref.nw,v 1.2 1993/05/06 18:15:40 jgk Exp $
  90. nawk '<<noxref.awk>>'
  91. <<noxref.bat>>=
  92. @echo off
  93. REM # $Id: noxref.nw,v 1.2 1993/05/06 18:15:40 jgk Exp $
  94. REM The NOWEB environment variable must be set to the directory
  95. REM where NOXREF.AWK is.  It must end in '/' or '\' as required
  96. REM by the AWK interpreter in use.
  97. awk -f %NOWEB%noxref.awk
  98. <<noxref.awk>>=
  99. # $Id: noxref.nw,v 1.2 1993/05/06 18:15:40 jgk Exp $
  100. <<Noxref awk source>>
  101. <<Noxref awk chunk list additions>>
  102. % ----------------------------------------------------------------------------
  103. \section{The AWK Source Code}
  104. This is mostly Ramsey's original code. The fragment that has been
  105. changed is included as the chunk: \LA{Find and process the \chklist\
  106. request}\RA.  Module label generation has been upgraded to the
  107. algorithm used in N~Ramsey's last release of the \noweb\ system.
  108. <<Noxref awk source>>=
  109. BEGIN { defns[0] = 0 ; uses[0] = 0 ; dcounts[0] = 0 ; firstdef[0] = 0; 
  110.               ucounts[0] = 0 ; idtable[0] = 0 ; keycounts[0] = 0 ;
  111.               firstdefnout[0] = 0; filetable[0] = 0 }
  112. { lines[nextline++] = $0 }
  113. /^@defn / { logname("DEFN", defns, dcounts, substr($0, 7)) }
  114. /^@use /  { logname("USE", uses, ucounts, substr($0, 6)) }
  115. /^@file / { curfile = modid(substr($0, 7) substr($0, 10, 3)) }
  116. <<Noxref awk source>>=
  117. function logname(which, tbl, counts, name, id) {
  118.   counts[name] = counts[name] + 1
  119.   id = which curfile "-" modid(name) "-" counts[name]
  120.   tbl[name] = tbl[name] id " "
  121.   lines[nextline++] = "@literal \\label{" id "}"
  122.   if (which == "DEFN" && firstdef[name] == "") firstdef[name] = id
  123. <<Noxref awk source>>=
  124. function modid(name, key) {
  125.   if (idtable[name] == "") {
  126.     key = name
  127.     gsub(/[\[\]\\{} -]/, "*", key)
  128.     if (length(key) > 6) key = substr(key,1,3) substr(key, length(key)-2, 3)
  129.     keycounts[key] = keycounts[key] + 1
  130.     idtable[name] = key "-" keycounts[key]
  131.   return idtable[name]
  132. <<Noxref awk source>>=
  133. END {
  134.   for (i=0; i < nextline; i++) {
  135.     name = substr(lines[i], 2)
  136.     name = substr(name, 1, index(name, " ")-1)
  137.     arg = substr(lines[i], length(name)+3)
  138.     if (name == "defn") {
  139.       thischunk = arg
  140.       printf "@defn %s~{\\footnotesize\\rm\\pageref{%s}}\n", arg, firstdef[arg]
  141.     } else if (name == "use") {
  142.       if (firstdef[arg] != "") 
  143.         printf "@use %s~{\\footnotesize\\rm\\pageref{%s}}\n", arg, firstdef[arg]
  144.       else
  145.         printf "@use %s~{\\footnotesize\\rm (never defined)}\n", arg
  146.     } else if (name == "end") {
  147.         if (substr(arg, 1, 4) == "code" && firstdefnout[thischunk] == 0) {
  148.           firstdefnout[thischunk] = 1
  149.           n = split(defns[thischunk], a)
  150.           if (n > 1) {
  151.             printf "@literal \\nwalsodefined{"
  152.             for (j = 2; j <= n; j++) 
  153.               printf "\\\\{%s}", a[j]
  154.             printf "}\n@nl\n"
  155.           }
  156.        if (uses[thischunk] != "") {
  157.           printf "@literal \\nwused{"
  158.             n = split(uses[thischunk], a)
  159.             for (j = 1; j <= n; j++) 
  160.               printf "\\\\{%s}", a[j]
  161.             printf "}\n@nl\n"
  162.           } else 
  163.               printf "@literal \\nwnotused\n@nl\n"
  164.         }
  165.         print lines[i]
  166.     }
  167.     <<Find and process the \chklist\ request>>
  168.     else
  169.         print lines[i]
  170.     delete lines[i]
  171. @ Finding the \chklist\ command is straight forward, it must be on a
  172. \verb+@text+ line.  The unclean way of using a chunk to insert an
  173. [[else]]~[[if]] clause in a larger [[if -- else if -- else]]
  174. structure should be noted.
  175. <<Find and process the \chklist\ request>>=
  176. else if (name == "text") {
  177.     if (arg == "\\nowebchunks") 
  178.         printChunkList()
  179.     else
  180.         print lines[i]
  181. @ If the keyword has been found the function [[printChunkList()]] is
  182. called to do the actual printing.
  183. % ----------------------------------------------------------------------------
  184. \section{The Chunk List Additions} 
  185. These additions consist, except for the chunk \LA{Find and process the
  186. \chklist\ request}\RA\ mentioned above, of two functions: one to sort
  187. the list of chunks, and one to print this list.
  188. <<Noxref awk chunk list additions>>=
  189. <<Sort chunk list>>
  190. <<Print chunk list>>
  191. % ----------------------------------------------------------------------------
  192. \subsection{The Sorting Routine}
  193. This function implements essentially a simple insertion sort.  If
  194. performance becomes a problem, some effort could be invested to use a
  195. better algorithm, but that seems unnecessary at the moment.
  196. \subsubsection{The Sorting Function Framework}
  197. Two global variables, [[nextFreeIdx]] and [[sortedNames]], carry the
  198. results of this function.  
  199. The [[sortedNames]] array is empty to start with, except for the
  200. first element, which contains the null string as a sentinel; no
  201. string compares to less than the null string.  The invariant on this
  202. array is that it will always contain chunk names in sorted order,
  203. with the lowest (according to the awk comparison rules) coming first.
  204. The invariant on [[nextFreeIdx]] is that it always contains the index
  205. number of the next free element in the array.
  206. <<Sort chunk list>>=
  207. function sortChunkNames(     <<Sort --- Local Variables>>)
  208.     sortedNames[0] = ""
  209.     nextFreeIdx=1;        #  The next index to use (range 1--N)
  210.     <<Run through the [[chunkname]]s as stored in [[defns]] array>>
  211.     <<Run through the [[chunkname]]s as stored in [[uses]] array>>
  212. \subsubsection{Scan the Arrays}
  213. All chunk names have been stored in the [[defns]] array when they were
  214. defined.  Using the ``{\tt for \em xyz \tt in \em arrayname}'' feature of
  215. awk, it is possible to step through all elements of the array.  The
  216. zero element in the arrays would confuse the sorting algorithm, so these
  217. elements have to be discarded. 
  218. <<Run through the [[chunkname]]s as stored in [[defns]] array>>=
  219. for (chunkname in defns) {
  220.     if (chunkname != 0) {
  221.         <<Insert in proper place in sorted array>>
  222.         } 
  223. <<Sort --- Local Variables>>=
  224. chunkname,
  225. @ All names that have been used are stored in the array [[uses]].  This
  226. array has to be scanned for chunk names that might have been used, but
  227. that were not defined.  Such chunks should also be included in the chunk
  228. list, so they are inserted in the [[sortedNames]] array.
  229. <<Run through the [[chunkname]]s as stored in [[uses]] array>>=
  230. for (chunkname in uses) {
  231.     if ((chunkname != 0) && !(chunkname in defns)) {
  232.         <<Insert in proper place in sorted array>>
  233.         } 
  234. \subsubsection{Insert into the Sorted Array}
  235. The proper place for the insertion is found by scanning the sorted
  236. array from the end to the beginning.  The local variable [[idx]] is
  237. used for this scan, it will always point at a possible insertion
  238. location.  [[nextFreeIdx]] is incremented, since it is now known that
  239. there is another element which will be inserted.
  240. If the element before the current scan location is greater than the
  241. chunkname to be inserted, then the chunkname will be inserted before
  242. that element.  The scanned element should be moved one position up (to
  243. the current insertion location) at this point.
  244. Otherwise, the chunk name should come after the element before the
  245. scan location, ie. it should be inserted at the current position.
  246. [[idx]] is pushed to the end condition, to stop the scan over the
  247. sorted array and to get a new chunk name.
  248. <<Insert in proper place in sorted array>>=
  249. for ( idx = nextFreeIdx++ ; idx>0 ; idx-- ) {
  250.     if ( sortedNames[idx-1] > chunkname )
  251.         sortedNames[idx] = sortedNames[idx-1] ;
  252.     else {
  253.         sortedNames[idx] = chunkname ;
  254.         idx = -1 ;
  255. <<Sort --- Local Variables>>=
  256. % ----------------------------------------------------------------------------
  257. \subsection{Print the Chunk List}
  258. The function to print the chunk list, first calls upon the sorting 
  259. function to get the names in order.  It then inserts, if required,
  260. some heading material and lastly prints the names.
  261. <<Print chunk list>>=
  262. function printChunkList(    <<Print --- Local Variables>> )
  263.     sortChunkNames() ;
  264.     <<Optional Header material>>
  265.     <<Header material>>
  266.     <<Print Loop>>
  267.     <<Closing Material>>
  268. % ----------------------------------------------------------------------------
  269. \subsubsection{The Printing Loop}
  270. This loops steps through the indices of the sorted names array, up to
  271. the next free index number.  It prints each name, using the \markup\
  272. \verb+@use+ directive, followed by a row of dots.  The printing of the
  273. page numbers, root markers etc. is delegated to the chunk \LA{print page
  274. numbers etc.}\RA.
  275. <<Print Loop>>=
  276. for (idx=1; idx<nextFreeIdx; idx++) {
  277.         print "@use " sortedNames[idx] ;
  278.         print "@literal \\dotfill" ;
  279.     <<Print page numbers etc.>>
  280.         print "@nl" ;
  281. <<Print --- Local Variables>>=
  282. @ When printing the page references, the following cases should be considered.
  283. \begin{itemize}
  284. \item If a name does not appear in the [[uses]] array, it must have been
  285.     in the [[defns]] arrray. It is therefore a root chunk.
  286. \item If a name does not appear in the [[defns]] array, it is undefined in
  287.     the source file currently processed.
  288. \item If a name is defined, print the page references of the definitions.
  289. \item If a name is used, print the usage page references.
  290. \end{itemize}
  291. <<Print page numbers etc.>>=
  292. if (uses[sortedNames[idx]] == "") {
  293.     print "@literal { \\rm Root}," ;
  294. if (defns[sortedNames[idx]] == "") {
  295.     print "@literal { \\rm Undefined}" ;
  296. else {
  297.     <<Print definition page numbers>>
  298. if (uses[sortedNames[idx]] != "") {
  299.     <<Print usage page numbers>>
  300. \paragraph{Definition References.}
  301. Definition page references are derived from the [[defns]] arrays, by
  302. splitting them into fields with the [[split]] function.  The first one
  303. should not be preceded by a ``,'' (comma character), but all subsequent
  304. numbers (if any) should have a comma in front of them.  Page references
  305. for the defintions are printed underlined. 
  306. <<Print definition page numbers>>=
  307. n = split(defns[sortedNames[idx]], a)
  308. print "@literal { \\underline{\\pageref{" a[1] "}}}";
  309. if (2 <= n) 
  310.     for (j = 2; j <= n; j++) 
  311.         print "@literal {, \\underline{\\pageref{" a[j] "}}}";
  312. <<Print --- Local Variables>>=
  313. n, a, j
  314. \paragraph{Usage References.}
  315. The page references for the places where the chunks are used are
  316. obtained from the [[uses]] array.  These always have
  317. preceding text (definition page references or the word ``Undefined''),
  318. so these  should always have a ``,'' in front of them.
  319. <<Print usage page numbers>>=
  320. n = split(uses[sortedNames[idx]], a)
  321. for (j = 1; j <= n; j++) 
  322.     print "@literal {\\rm, \\pageref{" a[j] "}}";
  323. \paragraph{A Small Test.}
  324. Both chunk names should appear in the chunk list: one
  325. marked as ``Root'', the other as ``Undefined''.
  326. <<An unused (therefore root) chunk>>=
  327. <<An undefined chunk>>
  328. \pagebreak
  329. \subsubsection{List Opening and Closing Definitions}
  330. If required, some commands could be included to generate a chapter or
  331. section heading above the chunk list.  However, the author of this
  332. code prefers to have such sectioning commands under the control of the
  333. final document source file.
  334. Users who prefer to have these section commands automatically
  335. generated (like the Icon implementation of the \noxref\ program does)
  336. can redefine \LA{Optional Header material}\RA\ to be equal to the
  337. current definition of \LA{Not used header material}\RA.
  338. <<Optional Header material>>=
  339. <<Not used header material>>=
  340. print "@literal \\ifx\\chapter\\undefined\\section*"
  341. print "@literal {Alphabetical List of Chunk Names}" ;
  342. print "@literal \\else\\chapter"
  343. print "@literal {Alphabetical List of Chunk Names}" ;
  344. print "@literal \\fi"
  345. print "@nl" ;
  346. @ The following header material is required, it sets up the
  347. environment for the list.
  348. <<Header material>>=
  349. print "@literal {\\obeylines" ;
  350. print "@literal \\setlength{\\parindent}{0mm}" ;
  351. print "@literal \\setlength{\\parskip}{1.4ex}"  ;
  352. print "@nl" ;
  353. <<Closing Material>>=
  354. print "@literal }" ;
  355. % ----------------------------------------------------------------------------
  356. \newpage
  357. \section{References}
  358. % This is faked (ie, not a real LaTeX bibliography), since this file 
  359. % is likely to get included in other files, with other bibliographies. 
  360. \begin{description}
  361. \sfcode`\.=1000\relax
  362. \item[{\rm [1]~~~}]
  363. Aho AV.,  Kernighan BW., Weinberger PJ. 1988,
  364. {\sl The AWK Programming Language,}
  365. Addison-Wesley.
  366. \item[{\rm [2]~~~}]
  367. Ramsey N. 1992--1993,
  368. ``Literate Programming Tools Need Not Be Complex,''
  369. To be published in {\sl IEEE Software.} 1993.
  370. \end{description}
  371. % ----------------------------------------------------------------------------
  372. % This should go in RCS.sty!
  373. \newenvironment{RCSlog}%
  374. {\begin{trivlist} \item[]%
  375. \setlength{\parindent}{0mm}%
  376. \setlength{\parskip}{3ex}%
  377. \catcode`\$=12%
  378. \hbadness=10000\ignorespaces\obeycr}%
  379. {\end{trivlist}}
  380. \section{RCS Maintained Log}
  381. \begin{RCSlog}
  382. $Log: noxref.nw,v $
  383. Revision 1.2  1993/05/06  18:15:40  jgk
  384. Moved from using bold to underlining for the page references
  385. of definitions. (On advice of Lee Wittenberg.)
  386. A few linguistic improvements.  RCS ID strings included in progs.
  387. Revision 1.1  1993/05/01  21:08:21  JG~Krom
  388. Initial revision
  389. A version with the same code, but some errors and typos 
  390. in the documentation text was known as:
  391. Revision 1.1  1993/04/28  17:03:23  jgk
  392. Initial revision
  393. This file was derived from:
  394. ``NOXREF.BAT'' by L~Wittenberg and ``noxref'' By N~Ramsey.
  395. (No change log was available for these files.)
  396. And from:
  397. Log: noxref.awk
  398. Revision 1.5  1993/04/23  12:52:16  JG~Krom
  399. On advice of Lee Wittenberg, used the new way of label generation.
  400. Revision 1.4  1993/04/20  22:41:44  JG~Krom
  401. Improved layout of chunklist.
  402. Revision 1.3  1993/04/11  17:47:38  JG~Krom
  403. Indicate root chunks in the chunklist.
  404. Revision 1.2  1993/04/11  15:52:53  JG~Krom
  405. First stab at the chunklist command.
  406. Revision 1.1 1992/10/21 17:00:00 LEEW
  407. checked in with -k by JG~Krom at 1993/04/10 16:53:28
  408. Which in turn was also derived from: ``noxref'' By N~Ramsey.
  409. \end{RCSlog}
  410. % ----------------------------------------------------------------------------
  411. \newpage
  412. \section{Alphabetical List of Chunk Names}
  413. \nowebchunks
  414. % ----------------------------------------------------------------------------
  415. \input{noxref.ind}
  416. % ----------------------------------------------------------------------------
  417. \end{document}
  418. % End of noweb code
  419. %=============================================================================
  420.